;(function(window){
	function StickHeaderTable( el ) {
		this.el = el;
		
  		this._init();
	}


	StickHeaderTable.prototype._init = function() {
		var self = this;
		if($(this.el).find('thead').length > 0 && $(this.el).find('th').length > 0) {
			
			 var $t	   = $(this.el);
			this.$w =  $(window);
			this.$thead = $t.find('thead').clone();
			this.$col = $t.find('thead, tbody').clone();


			// Add class, remove margins, reset width and wrap table
			$t
			.addClass('sticky-enabled')
			.css({
				margin: 0,
				width: '100%'
			}).wrap('<div class="sticky-wrap" />');

			if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y');

			// Create new sticky table head (basic)
			$t.after('<table class="sticky-thead" />');

			// If <tbody> contains <th>, then we create sticky column and intersect (advanced)
			if($t.find('tbody th').length > 0) {
				$t.after('<table class="sticky-col" /><table class="sticky-intersect" />');
			}

			// Create shorthand for things
			this.$stickyHead  = $(this.el).siblings('.sticky-thead');
				this.$stickyCol   = $(this.el).siblings('.sticky-col');
				this.$stickyInsct = $(this.el).siblings('.sticky-intersect');
				this.$stickyWrap  = $(this.el).parent('.sticky-wrap');

			this.$stickyHead.append(this.$thead);

			this.$stickyCol
			.append(this.$col)
				.find('thead th:gt(0)').remove()
				.end()
				.find('tbody td').remove();

			this.$stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');
		}
		self.setWidths();

		$t.parent('.sticky-wrap').scroll($.throttle(15, function() {
			self.repositionStickyHead();
			self.repositionStickyCol();
		}));

		self.$w.load(function() {
			self.setWidths();
		})
		.resize($.debounce(250, function () {
			self.setWidths();
			self.repositionStickyHead();
			self.repositionStickyCol();
		}))
		.scroll($.throttle(15, function(){
			self.repositionStickyHead();
		}));

	}
	StickHeaderTable.prototype.setWidths =  function () {
		var self = this;
		var $t = $(this.el);
		$t
		.find('thead th').each(function (i) {
			self.$stickyHead.find('th').eq(i).width($(this).width());
		})
		.end()
		.find('tr').each(function (i) {
			self.$stickyCol.find('tr').eq(i).height($(this).height());
		});

		// Set width of sticky table head
		self.$stickyHead.width($t.width());

		// Set width of sticky table col
		self.$stickyCol.find('th').add(self.$stickyInsct.find('th')).width($t.find('thead th').width())
	};
	StickHeaderTable.prototype.repositionStickyHead =  function () {
		var $t = $(this.el);
		// Return value of calculated allowance
		var allowance = this.calcAllowance();
	
		// Check if wrapper parent is overflowing along the y-axis
		if($t.height() > this.$stickyWrap.height()) {
			// If it is overflowing (advanced layout)
			// Position sticky header based on wrapper scrollTop()
			if(this.$stickyWrap.scrollTop() > 0) {
				// When top of wrapping parent is out of view
				this.$stickyHead.add($stickyInsct).css({
					opacity: 1,
					top: $stickyWrap.scrollTop()
				});
			} else {
				// When top of wrapping parent is in view
				this.$stickyHead.add(this.$stickyInsct).css({
					opacity: 0,
					top: 0
				});
			}
		} else {
			// If it is not overflowing (basic layout)
			// Position sticky header based on viewport scrollTop
			if(this.$w.scrollTop() > $t.offset().top && this.$w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) {
				// When top of viewport is in the table itself
				this.$stickyHead.add(this.$stickyInsct).css({
					opacity: 1,
					top: this.$w.scrollTop() - $t.offset().top
				});
			} else {
				// When top of viewport is above or below table
				this.$stickyHead.add(this.$stickyInsct).css({
					opacity: 0,
					top: 0
				});
			}
		}
	}
	StickHeaderTable.prototype.repositionStickyCol = function () {
		var self = this;
		if(self.$stickyWrap.scrollLeft() > 0) {
			// When left of wrapping parent is out of view
			self.$stickyCol.add(self.$stickyInsct).css({
				opacity: 1,
				left: self.$stickyWrap.scrollLeft()
			});
		} else {
			// When left of wrapping parent is in view
			self.$stickyCol
			.css({ opacity: 0 })
			.add(self.$stickyInsct).css({ left: 0 });
		}
	};

	StickHeaderTable.prototype.calcAllowance = function () {
		var $t = $(this.el);
		var a = 0;
		// Calculate allowance
		$t.find('tbody tr:lt(3)').each(function () {
			a += $(this).height();
		});
		
		// Set fail safe limit (last three row might be too tall)
		// Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value
		if(a > this.$w.height()*0.25) {
			a = this.$w.height()*0.25;
		}
		
		// Add the height of sticky header
		a += this.$stickyHead.height();
		return a;
	};

	window.StickHeaderTable = StickHeaderTable;
})(window);